package controllers

import (
	"bytes"
	"gitee.com/igolang/imoney/internal/app/system/entities"
	"gitee.com/igolang/imoney/internal/app/system/entities/constants"
	"gitee.com/igolang/imoney/internal/app/system/services"
	"gitee.com/igolang/imoney/internal/common/httpResp"
	commonTools "gitee.com/igolang/imoney/internal/common/tools"
	"gitee.com/igolang/imoney/internal/core/logger"
	"gitee.com/igolang/imoney/internal/models/model"
	"gitee.com/igolang/imoney/internal/router/middleware"
	"gitee.com/igolang/pkg/xgin"
	"github.com/gin-gonic/gin"
	"github.com/pkg/errors"
	"slices"
	"strings"
)

func CheckToken(ctx *gin.Context) {
	r := httpResp.Response()
	path := ctx.FullPath()
	if path == "" {
		path = ctx.Request.URL.Path
	}
	routeInfo := xgin.Route(path, ctx.Request.Method)
	per, ok := routeInfo.Ext.(*entities.RoutePerm)
	if !ok || !per.Token {
		ctx.Next()
		return
	}

	userInfo, err := getUserInfo(ctx)
	if err != nil {
		logger.Log().Error("parse token userInfo info err", "err", err)
		if ctx.FullPath() != "/system/logout" {
			httpResp.ErrorResponse(httpResp.ErrCodeInvalidToken, r)
		}
		httpResp.AbortJSON(ctx, r)
		return
	}

	if userInfo.User.UserID == 0 {
		logger.Log().Debug("未解析到用户")
		httpResp.ErrorResponse(httpResp.ErrCodeInvalidToken, r)
		httpResp.AbortJSON(ctx, r)
		return
	}

	// 鉴权
	if !checkPermission(per, userInfo) {
		httpResp.ErrorResponse(httpResp.ErrCodeNoPermission, r)
		httpResp.AbortJSON(ctx, r)
		return
	}

	ctx.Set(constants.LoginUser, userInfo)
	ctx.Next()
}

func WrapperResponse(ctx *gin.Context) {
	blw := &middleware.ResponseWriterWrapper{Body: bytes.NewBufferString(""), ResponseWriter: ctx.Writer}
	ctx.Writer = blw
	ctx.Next() // next方法时会把context中的响应数据写到Body中，因为middleware.ResponseWriterWrapper重写了相关write方法
	// 处理响应
	copyCtx := ctx.Copy()
	copyCtx.Writer = blw
	services.OperLog.AddOperationLog(copyCtx, xgin.GetPath(ctx), blw.Body)
}

func getUserInfo(ctx *gin.Context) (*entities.LoginUserInfo, error) {
	token := ctx.GetHeader("Authorization")
	token = strings.ReplaceAll(token, "Bearer ", "")
	if token == "" {
		return nil, errors.New("token empty")
	}
	ctx.Set(constants.LoginTokenKey, token)
	if ctx.GetHeader("request_mode") == "debug" && commonTools.EnvLocal() {
		return &entities.LoginUserInfo{
			Permissions: []string{constants.AllPermission},
			Roles:       []string{constants.SuperAdmin},
			User: struct {
				*model.SysUser
				Dept  *model.SysDept   `json:"dept"`
				Roles []*model.SysRole `json:"roles"`
			}{
				SysUser: &model.SysUser{
					UserID:   1,
					UserName: constants.SuperAdmin,
					NickName: constants.SuperAdmin,
					DeptID:   constants.RootDeptId,
				},
				Dept: &model.SysDept{DeptID: constants.RootDeptId, DeptName: "ruoyi"},
			},
		}, nil
	}
	// 验证有效性
	return services.User.LoginUser(token)
}

func checkPermission(perm *entities.RoutePerm, userInfo *entities.LoginUserInfo) bool {
	// 明确定义无需验证token
	if !perm.Token || perm.Permission == "" {
		return true
	}

	if slices.Contains(userInfo.Roles, constants.SuperAdmin) {
		return true
	}

	if slices.Contains(userInfo.Permissions, constants.AllPermission) {
		return true
	}

	return slices.Contains(userInfo.Permissions, perm.Permission)
}
